﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Globalization;
using System.Net.NetworkInformation;
using System.Windows;
using NativeWifi;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.Windows.Threading;

namespace NetwerkScanner
{

    #region Access Point Scanner
    /// <summary>
    /// Gaat elke seconden op zoek naar de gedecteerde netwerken van elke wireless interface
    /// </summary>
    class AccessPointScanner
    {

        private WlanClient Client = new WlanClient();

        /// <summary>
        /// Start de Access Point scan
        /// </summary>
        public void Run()
        {
            Thread scanThread = new Thread(() =>
            {
                while (true)
                {
                    foreach (WlanClient.WlanInterface wlanIface in Client.Interfaces)
                    {
                        Wlan.WlanBssEntry[] bssList = wlanIface.GetNetworkBssList();

                        foreach (Wlan.WlanBssEntry bssEntry in bssList)
                        {
                            Wlan.Dot11Ssid ssid = bssEntry.dot11Ssid;
                            String networkName = Encoding.ASCII.GetString(ssid.SSID, 0, (int)ssid.SSIDLength);
                            BasicServiceSetDetectedEventArgs e = new BasicServiceSetDetectedEventArgs();
                            e.DetectedBasicServiceSet = new BasicServiceSet(networkName, bssEntry.rssi, BitConverter.ToString(bssEntry.dot11Bssid));
                            //Event handler op STA thread oproepen
                            try
                            {
                                Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
                                {
                                    App.Applicatie.BasicServiceSetDetectedEvent(e);
                                }));
                            }
                            catch (Exception ex)
                            {
                                App.Logger.WriteLine("AccessPointScanner", ex.Message);
                            }
                        }
                    }
                    Thread.Sleep(1000);
                }
            });
            scanThread.IsBackground = true;
            scanThread.Start();
        }
    }
    #endregion

    #region ARP Scanner
    class ARPScanner
    {

        #region Fields
        private string netwerk;
        private Process nmapProcess;
        private Thread thread;
        public bool klaar;
        #endregion

        #region Constructor
        public ARPScanner(string n)
        {
            netwerk = n;
        }
        #endregion

        /// <summary>
        /// Start de ARP scan
        /// </summary>
        public void Run()
        {
            thread = new Thread(() =>
            {
                Host huidigeHost = null;
                try
                {
                    ProcessStartInfo nmapProcessInfo = new ProcessStartInfo("nmap", "-sn " + netwerk);
                    nmapProcessInfo.UseShellExecute = false;
                    nmapProcessInfo.CreateNoWindow = true;
                    nmapProcessInfo.RedirectStandardOutput = true;
                    nmapProcessInfo.RedirectStandardError = true;
                    nmapProcess = new Process();
                    nmapProcess.StartInfo = nmapProcessInfo;
                    nmapProcess.Start();
                    StreamReader myStreamReader = nmapProcess.StandardOutput;
                    String s = "";
                    //Output van nmap.exe parsen
                    while ((s = myStreamReader.ReadLine()) != null)
                    {
                        if (s.StartsWith("Nmap scan report for "))
                        {
                            s = s.Substring("Nmap scan report for ".Length);
                            huidigeHost = new Host();
                            huidigeHost.IPAdres = s;
                        }
                        else if (s.StartsWith("MAC Address: "))
                        {
                            s = s.Substring("MAC Address: ".Length);
                            s = s.Substring(0, s.IndexOf(" "));

                            huidigeHost.MACAddress = s;
                            HostDetectedEventArgs e = new HostDetectedEventArgs();
                            e.DetectedHost = huidigeHost;
                            App.Applicatie.HostDetectedEvent(e);
                        }
                        else if (s.StartsWith("Host is up"))
                        {
                            s = s.Substring("Host is up".Length);
                            if (s.Contains("latency"))
                            {
                                s = s.Substring(2);
                                s = s.Substring(0, s.IndexOf("s"));
                                double d = Double.Parse(s, CultureInfo.InvariantCulture);
                                huidigeHost.Ping = (int)(d * 1000);
                            }

                        }
                    }
                    Console.WriteLine("ARP scan klaar");
                    nmapProcess.Close();
                    klaar = true;
                }
                catch (Exception e)
                {
                    App.Logger.WriteLine("NMAP ARP Scan", e.Message);
                }
            });
            thread.IsBackground = true;
            thread.Start();
        }

        /// <summary>
        /// Stopt de ARP scan door het bijbehorden nmap process te doden en bijbehorende thread af te sluiten
        /// </summary>
        public void Stop()
        {
            if (nmapProcess != null)
            {
                try
                {
                    nmapProcess.Kill();
                }
                catch
                {
                }
            }
            if (thread != null)
            {
                thread.Abort();
            }
            klaar = true;
        }

    }

    #endregion

    #region UDP Broadcast Sniffer
    class NetwerkSniffer
    {

        #region Fields
        private IPAddress ip;
        private Socket mainSocket;
        private byte[] byteData = new byte[4096];
        private bool stop;
        #endregion

        #region Constructor
        public NetwerkSniffer(IPAddress ip)
        {
            this.ip = ip;
        }
        #endregion


        /// <summary>
        /// Start de sniffer
        /// </summary>
        public void Run()
        {
            mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
            mainSocket.Bind(new IPEndPoint(ip, 0));
            mainSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);
            mainSocket.IOControl(IOControlCode.ReceiveAll, new byte[] { 1, 0, 0, 0 }, new byte[] { 1, 0, 0, 0 });
            mainSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), null);
        }

        /// <summary>
        /// Socket packet received event handler
        /// </summary>
        /// <param name="ar"></param>
        public void OnReceive(IAsyncResult ar)
        {
            try
            {
                //Lees het ontvangen packet in
                int nReceived = mainSocket.EndReceive(ar);
                IPHeader ipHeader = new IPHeader(byteData, nReceived);
                Host host = new Host();
                host.IPAdres = ipHeader.SourceAddress.ToString();
                HostDetectedEventArgs e = new HostDetectedEventArgs();
                e.DetectedHost = host;
                App.Applicatie.HostDetectedEvent(e);
                if (!stop)
                {
                    //Luister verder naar meer packets
                    mainSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), null);
                }
                else
                {
                    //Stop met luisteren
                    mainSocket.Close();
                }
            }
            catch (Exception e)
            {
                App.Logger.WriteLine("UDPSniffer", e.Message);
            }
        }

        /// <summary>
        /// Stopt de sniffer
        /// </summary>
        public void Stop()
        {
            stop = true;
        }

    }
    #endregion

    #region Event arguments
    public class HostDetectedEventArgs : EventArgs
    {
        public Host DetectedHost { get; set; }
    }

    public class BasicServiceSetDetectedEventArgs : EventArgs
    {
        public BasicServiceSet DetectedBasicServiceSet { get; set; }
    }
    #endregion

}
